<template>
	<view class="container">

		<!-- 壁纸轮播图 -->
		<swiper circular :current="currentIndex" @change="changeSwiper">
			<!-- 为了实现懒加载的效果，即预览哪张壁纸，才去加载哪张壁纸 -->
			<swiper-item v-for="(item, index) in previewWallpapers" :key="item._id">
				<image class="full-image" mode="aspectFill" v-if="preloadedWallpaperIds.has(index)" :src="item.picurl"
					@click="switchMask"></image>
			</swiper-item>
		</swiper>


		<!-- 壁纸上的遮罩层，显示图片的更多信息和操作界面 -->
		<view class="mask" v-if="maskShow">
			<!-- 切换上一个 -->
			<view class="to-back" 
			:style="{top: getBackIconTopInPreviewPage() + 'px' }"
			 @click="backPreviousPage">
				<uni-icons type="back" size="20" color="white"></uni-icons>
			</view>
			<view class="count">{{currentIndex + 1}} / {{previewWallpapers.length}}</view>
			<view class="time">
				<uni-dateformat :date="Date.now()" format="hh:mm"></uni-dateformat>
			</view>
			<view class="date">
				<uni-dateformat :date="Date.now()" format="MM月dd日"></uni-dateformat>
			</view>
			<view class="operation">
				<view class="box" @click="openPopUp">
					<uni-icons type="info" size="28"></uni-icons>
					<view class="text">信息</view>
				</view>
				<view class="box" @click="openStarsPopUp">
					<uni-icons type="star" size="28"></uni-icons>
					<view class="text">分数</view>
				</view>
				<view class="box" @click="downloadWallpaper">
					<uni-icons type="download" size="26"></uni-icons>
					<view class="text">下载</view>
				</view>
			</view>
		</view>

		<!-- 壁纸详情弹窗 -->
		<!-- 由于uni-app弹窗组件默认加了安全区域，而info-popup中也加了安全区域高度，
		故将uni-app弹窗组件中的安全区域去除即可 -->
		<uni-popup ref="infoPopUp" type="bottom" :safe-area="false">
			<view class="info-popup">

				<view class="pop-up-header">
					<view></view>
					<view class="title">壁纸信息</view>
					<view class="close" @click="closePopup">
						<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
					</view>
				</view>
				
				<scroll-view scroll-y>
					<view class="content">
						<view class="row">
							<view class="label">壁纸ID：</view>
							<text class="value" selectable>{{currentWallpaper._id}}</text>
						</view>
						<view class="row">
							<view class="label">分类：</view>
							<text class="value category" selectable>{{categoryName}}</text>
						</view>
						<view class="row">
							<view class="label">发布者：</view>
							<text class="value" selectable>咸虾米</text>
						</view>
						<view class="row">
							<view class="label" @click="openStarsPopUp">评分：</view>
							<view class="value rates">
								<uni-rate size="16" readonly touchable="false" :value="currentWallpaper.score">
								</uni-rate>
								<text class="score">{{currentWallpaper.score}}分</text>
							</view>
						</view>
						<view class="row">
							<view class="label">摘要：</view>
							<text class="value">
								{{currentWallpaper.description}}
							</text>
						</view>
						<view class="row">
							<view class="label">标签：</view>
							<view class="value tabs">
								<view class="tab" v-for="item in currentWallpaper.tabs" :key="item">
									{{item}}
								</view>
							</view>
						</view>

						<!-- 版权信息 -->
						<view class="copyright">
							特此声明：本小程序所涉及到的所有图片资源均采集于网络，
							若侵犯了您的著作权，请将壁纸ID反馈到邮箱 <text class="email">xxxxx@qq.com</text>，
							管理员在第一时间收到后，会马上下架该壁纸，感谢理解！
						</view>
					</view>
				</scroll-view>
			</view>


		</uni-popup>

		<!-- 壁纸打分弹窗 -->
		<uni-popup ref="starsPopUp" :is-mask-click="false">
			<view class="stars-pop-up">
				<view class="pop-up-header">
					<view></view>
					<view class="title">{{isScore ? '该壁纸已评分过了~' : '壁纸评分'}}</view>
					<view class="close" @click="closeStarsPopUp()">
						<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
					</view>
				</view>

				<view class="content">
					<uni-rate :disabled="isScore" allow-half disabled-color="#FFCA3E" v-model="userScore"></uni-rate>
					<text class="text">{{userScore}}分</text>
				</view>

				<view class="footer">
					<!-- 当 评分为0 或 已评分 时，才显示禁用按钮
					:disabled="!userScore || isScore"
					 -->
					<button :disabled="userScore===0 || isScore" type="default" size="mini" plain
						@click="submitScore">确认评分</button>
				</view>
			</view>
		</uni-popup>
	</view>
</template>

<script setup lang="ts">
	import { ref, watch } from 'vue'
	import { onLoad } from '@dcloudio/uni-app'
	import { getBackIconTopInPreviewPage } from '@/utils/system.js'
	import { IMAGES_BY_CATEGORY_STORAGE } from '@/common/constants/storage'
	import { apiSubmitScore, 
	apiSWallpaperDownloadRecord, 
	apiGetWallpaperDetailById } from '../../api/apis'
import { gotoHome } from '../../utils/common'

	/*
	 * 用来记录已经预加载过的壁纸索引
	 * 使用 Set 数据结构，避免重复存储同一个索引
	 * 例如：{0, 1, 2} 表示索引 0、1、2 的壁纸已经预览过
	 */
	const preloadedWallpaperIds = ref(new Set())

	/* 会随着轮播图滑动、或首次加载时设置
	 */
	const currentIndex = ref()


	/*
	 * 所有待预览的壁纸数组
	 * 从本地缓存中读取并加工 URL 后得到
	 */
	const previewWallpapers = ref([])

	const currentWallpaper = ref({})

	const categoryName = ref()
	/*
	 * 页面加载时触发
	 * 1. 从缓存中获取壁纸数据
	 * 2. 根据 params.id 找到该壁纸的索引，设置为当前索引
	 * 3. 把当前壁纸索引加入预加载集合
	 */
	onLoad( async (params) => {
		
		// 从本地缓存中读取并设置预览壁纸数组
		getPreviewWallpapersFromStorage()

		const { id, type } = params
		if(!id) { // 当前页面加载时，缺少目标壁纸id
			gotoHome()
			return 
		}
		
		if(type === 'share') {
			// 此页面是通过他人分享进来的，此时当前用户本地是无缓存的
			const res = await apiGetWallpaperDetailById({id})
			// 为了获取高清壁纸图，需修改下数组中的元素后缀
			previewWallpapers.value = res.data.map(item => {
				return {
					...item,
					// 把小图地址替换成大图地址
					picurl: item.smallPicurl.replace('_small.webp', '.jpg')
				}
			})
		}
		categoryName.value = params.categoryName
		// 根据传入的 id 找到对应的索引，如果找不到则设为 0
		const idx = previewWallpapers.value.findIndex(item => item._id === id)
		currentIndex.value = idx !== -1 ? idx : 0

		// 首次进入页面时，也要进行加载
		preLoadPreviousAndNextOnCurrent()

		// 获取当前壁纸的详情
		currentWallpaper.value = previewWallpapers.value[currentIndex.value]
	})
	
	// 分享给好友
	onShareAppMessage(e => {
		return {
			title: '咸虾米壁纸',
			path: `pages/preview/preview?id=${currentWallpaper.value._id}&type=share`
		}
	}) 
	
	// 分享到朋友圈
	onShareTimeline(() => {
		return {
			title: '咸虾米壁纸',
			query: `id=${currentWallpaper.value._id}&type=share`
		}
	}) 

	const preLoadPreviousAndNextOnCurrent = () => {
		// 计算前一张索引
		let previousIndex = currentIndex.value - 1
		// 计算后一张索引
		let nextIndex = currentIndex.value + 1

		// 如果是第一张，前一张应该是最后一张（循环效果）
		previousIndex = previousIndex < 0
			? (previewWallpapers.value.length - 1)
			: previousIndex

		// 如果是最后一张，后一张应该是第一张（循环效果）
		nextIndex = nextIndex >= previewWallpapers.value.length
			? 0
			: nextIndex

		// 将前一张、当前、后一张的索引记录到 Set 中
		preloadedWallpaperIds.value.add(previousIndex)
		preloadedWallpaperIds.value.add(currentIndex.value)
		preloadedWallpaperIds.value.add(nextIndex)
	}

	/*
	 * 轮播图滑动结束时触发
	 * e.detail.current 表示新的索引
	 * 更新 currentIndex，同时记录新索引到预加载集合     
	 */
	const changeSwiper = (e) => {
		const { detail: { current } } = e
		currentIndex.value = current
		preloadedWallpaperIds.value.add(current)

		// 当轮播图进行滑动的时候，就进行预加载前后壁纸
		preLoadPreviousAndNextOnCurrent()

		// 当轮播图滑动完毕时，切换当前壁纸的信息
		currentWallpaper.value = previewWallpapers.value[currentIndex.value]
	}

	/**
	 * 从本地缓存读取所有待预览的壁纸
	 * 同时把缩略图 URL 替换成大图 URL
	 */
	const getPreviewWallpapersFromStorage = () => {
		const imagesByCategory = uni.getStorageSync(IMAGES_BY_CATEGORY_STORAGE) || []
		previewWallpapers.value = imagesByCategory.map(item => ({
			...item,
			// 把小图地址替换成大图地址
			picurl: item.smallPicurl.replace('_small.webp', '.jpg')
		}))
	}

	
	const backPreviousPage = () => {
		const returnResult = getCurrentPages()
		// 默认返回到上一页面
		
		uni.navigateBack({
			success: () => {
				
			},
			fail: (err) => { // 若返回不到上一页，默认重新发射到首页
			// reLanuch之后，会清空页面栈
				uni.reLaunch({
					url: '/pages/index/index'
				})
			}
		})

	}
	// 遮罩层是否显示
	const maskShow = ref(true)
	// 点击图片时，切换遮罩层的状态：显示/隐藏
	const switchMask = () => {
		maskShow.value = !maskShow.value
	}

	// 壁纸信息的数据相关
	const infoPopUp = ref(null)
	const openPopUp = () => {
		infoPopUp.value.open()
	}
	const closePopup = () => {
		infoPopUp.value.close()
	}

	// 用户评分弹窗的相关数据
	const userScore = ref(0)
	const starsPopUp = ref(null)
	const isScore = ref(false) // 根据currentWallpaper的userScore是否存在 判断该壁纸是否被打分
	const openStarsPopUp = () => {
		// 先判断当前壁纸是否已打分
		if (currentWallpaper.value.userScore) {
			isScore.value = true
			// 若已打分，更新打分分数
			userScore.value = currentWallpaper.value.userScore
		}
		starsPopUp.value.open()
	}
	const closeStarsPopUp = () => {
		starsPopUp.value.close()
		// 做收尾工作.为下一张壁纸的是否已打分 初始化数据
		userScore.value = 0
		// 加一个定时器，使得评分弹窗关闭的瞬间，评分弹窗的标题稍后改变
		setTimeout(() => {
			isScore.value = false
		}, 100)

	}

	const submitScore = async () => {
		const data = {
			classid: currentWallpaper.value.classid,
			wallId: currentWallpaper.value._id,
			userScore: userScore.value
		}

		const res = await apiSubmitScore(data)
		console.log('preview: res:', res)
		if (res.errCode === 0) {
			uni.showToast({
				// 打分成功，显示评分弹窗
				icon: 'none',
				title: '评分完成！'
			})

			// 当前壁纸已评分，给当前壁纸新增属性userScore，表示此壁纸已被当前用户打分
			// 然后更新本地缓存
			previewWallpapers.value[currentIndex.value].userScore = userScore.value
			uni.setStorageSync(IMAGES_BY_CATEGORY_STORAGE, previewWallpapers.value)

			// 紧接着关闭评分窗口
			closeStarsPopUp()
		}

	}

	// 把回调API封装成Promise
	const getImageInfo = (src) => {
		return new Promise((resolve, reject) => {
			uni.getImageInfo({
				src,
				success: resolve,
				fail: reject
			})
		})
	}

	const saveImageToPhotosAlbum = (filePath) => {
		return new Promise((resolve, reject) => {
			uni.saveImageToPhotosAlbum({
				filePath,
				success: resolve,
				fail: reject
			})
		})
	}

	const openSetting = () => {
		return new Promise((resolve) => {
			uni.openSetting({
				success: resolve,
				fail: resolve
			})
		})
	}

	// 下载壁纸函数
	const downloadWallpaper = async () => {
		// #ifdef H5
		uni.showModal({
			content: '长按壁纸进行下载',
			showCancel: false
		})
		// #endif

		// #ifndef H5
		
		uni.showLoading({
			title: '加载壁纸中...',
			mask: true
		})
		// 用户尝试下载壁纸时，就将 下载壁纸记录 记录到后台
		const data = {
			classid: currentWallpaper.value.classid,
			wallId: currentWallpaper.value._id
		}
		const res = await apiSWallpaperDownloadRecord(data)
		try {
			// 1. 获取临时图片路径
			const { path } = await getImageInfo(currentWallpaper.value.picurl)

			// 2. 保存到相册
			await saveImageToPhotosAlbum(path)

			uni.showToast({
				title: '保存成功',
				icon: 'success'
			})
		} catch (err) {
			console.log('保存失败:', err)

			// 用户取消保存
			if (err.errMsg === 'saveImageToPhotosAlbum:fail cancel') {
				uni.showToast({
					title: "保存失败，请重新点击'下载'按钮",
					duration: 3000,
					icon: 'none'
				})
			} else {
				// 保存失败 除去 用户取消保存之后 的所有情况
				// 需要用户授权
				const modalRes = await new Promise((resolve) => {
					uni.showModal({
						title: '温馨提示',
						content: '需要您授权保存到相册的权限',
						success: resolve
					})
				})

				if (modalRes.confirm) {
					const setting = await openSetting()
					if (setting.authSetting['scope.writePhotosAlbum']) {
						uni.showToast({
							title: '获取授权成功，请再次点击下载',
							icon: 'none'
						})
					} else {
						uni.showToast({
							title: '获取授权失败',
							icon: 'none'
						})
					}
				}
			}
		} finally {
			uni.hideLoading()
		}
		// #endif
	}
		


	/*
	// 下载壁纸到本地
	const downloadWallpaper = () => {
		// #ifdef H5
		uni.showModal({
			content: '长按壁纸进行下载',
			showCancel: false
		})
		// #endif

		// #ifndef H5
		
		// 由于需要加载网络图片到临时目录，故须等待稍许，故加上一个加载中	
		uni.showLoading({
			title: '加载壁纸中...',
			mask: true
		})
		uni.getImageInfo({
			src: currentWallpaper.value.picurl,
			success: (res) => {
				// 由于saveImageToPhotosAlbum中的参数filePath 图片文件路径
				// 可以是临时文件路径也可以是永久文件路径，
				// 不支持网络图片路径
				const { path } = res
				console.log('path:', path)
				uni.saveImageToPhotosAlbum({
					filePath: path,
					success: (res) => {
						console.log('preview: res:', res)
					},
					// 当保存壁纸到相册失败时，自动执行此函数
					fail: (err) => {
						// 当用户马上保存图片成功时，若点击了取消
						if(err.errMsg == 'saveImageToPhotosAlbum:fail cancel'){
							uni.showToast({
								title: "保存失败，请重新点击'下载'按钮",
								duration: 3000,
								icon: 'none'
							})
							return 
						}
						uni.showModal({
							title: '温馨提示',
							content: '需要您授权保存到相册权限',
							success: (res) => {
								if (res.confirm) {
									uni.openSetting({
										success: (setting) => {
											console.log('setting:', setting)
											if(setting.authSetting['scope.writePhotosAlbum']){
												uni.showToast({
													title: '获取授权成功',
													icon: 'none'
												})
											} else {
												uni.showToast({
													title: '获取授权失败',
													icon: 'none'
												})
											}
										}
									})
								}
							}
						})
					},
					complete: () => {
						uni.hideLoading()
					}
				})
			},

		})
		// #endif
	}
	*/
</script>

<style lang="scss" scoped>
	/* 容器本身占满整个屏幕 */
	.container {
		position: relative;

		/* swiper 占满容器 */
		swiper {
			width: 100%;
			height: 100vh;

			swiper-item {
				width: 100%;
				height: 100%;

				image {
					width: 100%;
					height: 100%;
				}
			}
		}

		.mask {
			// position: absolute;
			// top: 0;
			// left: 0;
			// width: 100%;
			// height: 100%;
			// background-color: white;
			// opacity: 0.7;

			// &：表示mask类选择器  >：表示仅选择mask类选择器中的一级子元素
			// 设置一下通用样式
			&>view {
				position: absolute;
				left: 0;
				right: 0;
				margin: auto;
				// 元素的宽度根据其内容自动调整，同时允许元素保持块级特性。
				width: fit-content;
				color: #fff;
			}

			.to-back {
				display: flex;
				justify-content: center;
				align-items: center;
				width: 64rpx;
				height: 64rpx;
				// top: 30rpx;
				left: 30rpx;
				margin-left: 0;
				border: 1rpx solid rgba(255, 255, 255, 0.3);
				border-radius: 32rpx;
				background: rgba(0, 0, 0, 0.5);
				backdrop-filter: blur(10rpx);
			}

			.count {
				top: 10vh;
				/* 
		  该段代码也能实现水平居中
		  left: 0;
		  right: 0;
		  margin: auto;
		  width: fit-content; 
		  */
				/* 将元素的左边缘定位到父容器的水平中点 */
				// left: 50%;
				/* 
		   * 通过 transform 的 translate 函数将元素向左移动自身宽度的一半，
		   * 从而实现水平居中（因为 left:50% 是基于父容器，而 translate 是基于自身宽度）
		   * 参数说明：
		   *   - translate(-50%, 0)：
		   *     - -50%：水平方向向左移动 50% 的自身宽度（负值表示左移）
		   *     - 0：垂直方向不移动
		   */
				// transform: translate(-50%, 0);
				border-radius: 40rpx;
				padding: 8rpx 28rpx;
				background: rgba(0, 0, 0, 0.3);
				backdrop-filter: blur(10rpx);
				font-size: 28rpx;
			}

			.time {
				top: calc(10vh + 80rpx);
				font-size: 140rpx;
				// font-weight: 100;
				line-height: 1em; // 行高为字体高度的1倍
				text-shadow: 0 4rpx rgba(0, 0, 0, 0.3);
			}

			.date {
				font-size: 34rpx;
				top: calc(10vh + 230rpx);
				text-shadow: 0 4rpx rgba(0, 0, 0, 0.3);
			}

			.operation {
				bottom: 10vh;
				width: 65vw;
				height: 120rpx;
				border-radius: 60rpx;
				color: black;
				background: rgba(255, 255, 255, 0.8);
				display: flex;
				justify-content: space-around;
				align-items: center;
				//x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影颜色
				box-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.1);
				backdrop-filter: blur(20rpx);

				.box {
					display: flex;
					flex-direction: column;
					justify-content: center;
					align-items: center;
					// 设置一下内边距，便于用户点击
					padding: 2rpx 10rpx;

					.text {
						font-size: 26rpx;
						color: $text-font-color-2;
					}

					&:nth-child(3) {
						.text {
							// padding-top: 5rpx;
						}
					}
				}

			}
		}

		.pop-up-header {
			display: flex;
			justify-content: space-between;
			align-items: center;

			.title {
				color: $text-font-color-2;
				font-size: 26rpx;
			}

			.close {
				// border: 1px solid;
				padding: 6rpx;
			}
		}

		.info-popup {
			background: white;
			border-radius: 30rpx 30rpx 0 0;
			padding: 30rpx;
			overflow: hidden;

			scroll-view {
				max-height: 60vh;

				.content {
					.row {
						display: flex;
						padding: 16rpx 0;
						font-size: 32rpx;
						line-height: 1.7em; // 行高为字体的1.7倍

						.label {
							// margin-right: 20rpx;
							width: 140rpx;
							color: $text-font-color-3;
							text-align: right;
							font-size: 30rpx;
						}

						.value {
							flex: 1; // 自动占满父元素的空闲宽度
							// width: 0;
						}

						.category {
							color: $brand-theme-color;
						}

						.rates {
							display: flex;
							align-items: center;

							.score {
								padding-left: 10rpx;
								font-size: 26rpx;
								color: $text-font-color-3;
							}
						}

						.tabs {
							display: flex;
							flex-wrap: wrap; // 一行遮不下时，进行换行

							.tab {
								border: 1rpx solid $brand-theme-color;
								border-radius: 40rpx;
								margin-right: 10rpx;
								padding: 10rpx 30rpx;
								color: $brand-theme-color;
								font-size: 22rpx;
								line-height: 1rem;
							}
						}
					}

					.copyright {
						margin: 20rpx 0;
						border-radius: 10rpx;
						padding: 20rpx;
						font-size: 28rpx;
						line-height: 1.5rem;
						background: #f6f6f6;
						color: #666;

						.email {
							color: $brand-theme-color;
						}
					}
				}
			}
		}

		.stars-pop-up {
			background: white;
			border-radius: 20rpx;
			padding: 30rpx;
			width: 70vw;

			.content {
				display: flex;
				justify-content: center;
				align-items: center;
				padding: 30rpx 0;

				.text {
					text-align: right;
					padding-left: 6rpx;
					width: 80rpx;
					line-height: 1em;
					color: #ffca3e;
				}
			}

			.footer {
				text-align: center;
			}
		}
	}
</style>